#include "BuiltInCommand.h"

BuiltInCommand::BuiltInCommand( string command, vector<string> * arguments  ) {
	this->command_str = command;
	this->arguments = arguments;
	backgroundPids = new vector<int>();
}

BuiltInCommand::~BuiltInCommand() {
	delete backgroundPids;
}

void BuiltInCommand::executeBuildInCommand() {
	const char * command = command_str.c_str();
	int argc = arguments->size();
	char * argv[arguments->size()];
	for(unsigned int j=0; j<arguments->size();j++){
		argv[j] = const_cast<char*>(arguments->at(j).c_str()); // o_0 completely fubar
	}
	argv[arguments->size()] = NULL; // null

	if( strcmp( command, "cd" ) == 0 ) {
		cd( argc, argv );
	} else if( strcmp( command, "jobs") ) {
		jobs();
	} else if( strcmp( command, "nice") ) {
		if( argc >= 3 ) {
			nice( argc, argv );
		}
	} else if( strcmp( command, "wait" ) == 0 ) {
		if( argc == 2 ) {
			wait( atoi( argv[1] ) );
		}
	}
}

void BuiltInCommand::setPids( vector<int>* backgroundPids ){
	this->backgroundPids = backgroundPids;
}

//***************//
//Private methods//
//***************//

int BuiltInCommand::cd( int argc, char* argv[] ) {
	int option;
	char* directory;

	const char* help = (char*) "Usage: ";

	while ( ( option = getopt( argc, argv, "h" ) ) != -1) {
		switch( option ) {

		case 'h':
			fprintf(stdout, "%s\n", help);
			break;

		case '?':

		default:
			abort();
			break;
		}
	}

	if( strcmp( argv[argc - 1], "cd" ) == 0 ) {
		//If no parameters, change to home directory!
		directory = getenv( "HOME" );
	} else {
		directory = argv[argc - 1];

		DIR* dir = opendir( directory );
		if( dir == 0 ) {
			fprintf( stderr, "The specified path does not exist.\n");
			return -1;
		} else {
			closedir( dir );
		}
	}
	return chdir( directory );
}

void BuiltInCommand::nice( int argc, char* argv[] ) {
	int increment = atoi( argv[1] );

	if( increment < 0 ) {
		cout << "Syntax Error!" << endl;
	} else {
		if( increment == 0 ) {
			cout << "Please enter a correct increment!" << endl;
		} else {
			Command* command = new Command( command_str );
			command->setPriority( increment );
			command->execute();

			delete command;
		}
	}
}

void BuiltInCommand::jobs() {
	int index = 1;

	for( vector<int>::iterator iter = backgroundPids->begin(); iter != backgroundPids->end(); iter++ ) {
		string info = getProcessInfo(*iter, index );
		if( strcmp( info.c_str(), "Terminated" ) == 0 ) {

		} else {
			cout << info << endl;
		}
		index++;
	}
}

void BuiltInCommand::wait( pid_t childPid ) {
	int status = -1;

	if( childPid > 0 ) {
		do {
			pid_t errorCheck = waitpid( childPid, &status, WUNTRACED | WCONTINUED );
			if( errorCheck == -1 ) {
				perror( "waitpid" );
				break;
				//exit(EXIT_FAILURE);
			}
			if( WIFEXITED( status ) ) {
				if( status != 0 ) {
					printf( "exited, status=%d\n", WEXITSTATUS( status ) );
				}
			} else if( WIFSIGNALED( status ) ) {
				printf( "killed by signal %d\n", WTERMSIG( status ) );
			} else if( WIFSTOPPED( status ) ) {
				printf( "stopped by signal %d\n", WSTOPSIG( status ) );
			} else if( WIFCONTINUED( status ) ) {
				printf( "continued\n" );
			}
		} while( !WIFEXITED( status ) && !WIFSIGNALED( status ) );

		if( status != 0 ) {
			cout << "Process: " << childPid << endl;
		}
	} else {
		cout << "Not a (positive) number" << endl;
	}
}

string BuiltInCommand::getProcessInfo( int processID, int position ) {
	string processInfo = "";
	string dir = ( "/proc/" + integerToString( processID ) + "/stat" );

	FILE* stat = fopen(dir.c_str(), "r");
	if( stat != 0 ) {
		char name[80];
		char state;
		fscanf( stat, "%*d %s %c", name, &state );
		if( name != 0 ) {
			processInfo = ( "[" + integerToString( processID ) + "]\t" + integerToString( position )
							+ "\t" + state + '\t' + name + "\n" );
		} else {
			return "Terminated";
		}
		fclose( stat );
	}
	return processInfo;
}

string BuiltInCommand::integerToString( int integer ) {
	stringstream ss;
    ss << integer;
    return ss.str();
}
